Časovač

python.edumach.cz

V předchozí kapitole jsme v místě kliknutí nakreslili barevné kroužky podle určité podmínky. Abychom nakreslili více kroužků, museli jsme kliknout myší vícekrát. To můžeme prozatím vyřešit pomocí smyčky for – nakreslíme více kroužků najednou na náhodném místě.

#############
#  14_1.py  #
#############

import tkinter
import random

canvas = tkinter.Canvas()
canvas.pack()

def krouzek():
    x = random.randrange(450)
    y = random.randrange(320)
    if 100<x<150 or 50<y<100:
        canvas.create_oval(x-5, y-5, x+5, y+5, fill='green')
    else:
        canvas.create_oval(x-5, y-5, x+5, y+5, fill='yellow')

for i in range(1, 1000):
    krouzek()

canvas.mainloop() #povinné ve VSCode

Smyčku for již můžeme upravit tak, aby se jednotlivé iterace prováděly postupně s určitým časovým zpožděním. K tomu jsme použili canvas.after() a canvas.update(). Takto upravíme smyčku for, aby se vykreslovala postupně.

for i in range(1, 1000):
    krouzek()
    canvas.update()
    canvas.after(10)

Smyčku for používáme v situacích, kdy můžeme předem odhadnout počet opakování. Proto se jí říká cyklus s pevným počtem opakování. Existují však situace, kdy potřebujeme akci opakovat v pravidelných intervalech a přesný počet opakování předem neznáme. K řešení takového problému můžeme použít tzv. časovač, který v pravidelných časových intervalech opakuje zadanou posloupnost příkazů. K tomu slouží příkaz canvas.after(time, function), kterému zadáme nejen čas v milisekundách, ale také název funkce, která se má po pozastavení programu provést.

Náš program po úpravě pomocí časovače:

#############
#  14_2.py  #
#############

import tkinter
import random

canvas = tkinter.Canvas(width=450,height=320)
canvas.pack()

def krouzek():
    x = random.randrange(450)
    y = random.randrange(320)
    if 100<x<150 or 50<y<100:
        canvas.create_oval(x-5, y-5, x+5, y+5, fill='green')
    else:
        canvas.create_oval(x-5, y-5, x+5, y+5, fill='yellow')
    canvas.after(10, krouzek)

def ctverec():
    x = random.randrange(450)
    y = random.randrange(320)
    if 100<x<150 or 50<y<100:
        canvas.create_rectangle(x-5, y-5, x+5, y+5, fill='red')
    else:
        canvas.create_rectangle(x-5, y-5, x+5, y+5, fill='blue')
    canvas.after(30, ctverec)

ctverec()
krouzek()

canvas.mainloop() #povinné ve VSCode

Program po nějaké době vykreslí takový obrázek:

Následující program postupně nakreslí několik kuliček.

#############
#  14_3.py  #
#############

import tkinter

canvas = tkinter.Canvas(width=400,height=300)
canvas.pack()

def micek():
    global x
    global y
    canvas.create_oval(x-5, y-5, x+5, y+5)
    y = y+5
    if y<200:
        canvas.after(100, micek)
	
x = 200
y = 5

micek()

canvas.mainloop() #povinné ve VSCode

Všimněte si, že jsme v programu nastavili proměnnou x na 200 a y na 5. V těchto proměnných jsou souřadnice, na kterých je nakreslena první kulička. Po nastavení proměnných spustíme funkci micek. Tato funkce nakreslí kuličku (kruh) na souřadnice podle hodnot proměnných x a y. Další kuličku chceme nakreslit na souřadnice, které jsou uvedeny v proměnných x a y. Další chceme nakreslit o 5 bodů níže. Proto zvýšíme y o 5, takže napíšeme y = y + 5. Protože jsme ve funkci micek, nemůžeme zde normálně měnit hodnotu proměnné, která se používá v hlavním programu mimo naši funkci. Jak y, tak x jsou globální proměnné, nikoli lokální proměnné ve funkci, kde je chceme změnit. V takových situaci musíme použít příkaz global a název proměnné, abychom funkci sdělili, že chceme pracovat s proměnnou globální proměnná. Nyní má y hodnotu 10. V dalším řádku se ptáme, zda je y menší než 200, a to pouze v případě, že je tato podmínka splněna, naplánujeme další provedení funkce micek na 100 milisekund. Vidíme, že jsme vytvořili časovač, který neopakuje příkazy donekonečna, ale jen tak dlouho, dokud je splněna podmínka. Po spuštění programu uvidíme, že se pod sebou vykresluje několik kuliček.

Pomocí canvas.delete('all') můžeme odstranit vše, co jsme nakreslili. Pokud tento příkaz napíšeme na začátku funkce, funkce pokaždé vymaže vše nakreslené a my uvidíme pouze poslední nakreslený objekt. To je princip animace. Nejprve vymažeme původní obrázky a nakreslíme stejný tvar postupně v posunuté poloze.

def micek():
    global x
    global y
    canvas.delete('all')
    canvas.create_oval(x-5, y-5, x+5, y+5)
    y = y+5
    if y<200:
        canvas.after(100, micek)

❓Otázky

  1. Co tento program udělá, když obrátíme pořadí create_oval a delete?

  2. Na které souřadnici bude nakreslen poslední obrazec?

  3. Co udělá tento program, pokud nahradíme podmínku touto y == 200?

  4. Co program udělá, jestliže zvětšíme y o 6 (y = y + 6) a nahradíme podmínku následující: y == 200?

💾 Úkoly

Kulička vodorovně vpravo

Vytvořte program 14_vodorovne.py, který přesune kuličku vodorovně od levého okraje k pravému okraji.

Kulička šikmo dolů

Vytvořte program 14_sikmo.py, ve kterém se bude kulička pohybovat šikmo dolů.

Kulička svisle dolů

Vytvořte program 14_nahoru_dolu.py, ve kterém bude kulička padat svisle shora dolů. Po dosažení spodní hrany se její pohyb obrátí – bude se posouvat opět nahoru. Takto stále dokola.

Co program dělá (1)

Odhadněte, co udělá následující program:

#############
#  14_4.py  #
#############

import tkinter

canvas = tkinter.Canvas(width=400,height=300)
canvas.pack()

def micek():
    global x
    global y
    global pokracovat
    canvas.delete('all')
    canvas.create_oval(x-5, y-5, x+5, y+5)
    y = y + 5
    if y > 250:
        y = 5
    if pokracovat == 1:
        canvas.after(100, micek)

def stop(souradnice):
    global pokracovat
    pokracovat = 0
	
pokracovat = 1
x = 200
y = 5
micek()

canvas.bind('<ButtonPress-1>', stop)

canvas.mainloop() #povinné ve VSCode

Co program dělá (2)

Odhadněte, co udělá následující program:

#############
#  14_5.py  #
#############

import tkinter

canvas = tkinter.Canvas(width=400,height=300)
canvas.pack()

def micek():
    global x
    global y
    global pokracovat
    canvas.delete('all')
    canvas.create_oval(x-5, y-5, x+5, y+5)
    y = y + 5
    if y > 250:
        y = 5
    if pokracovat == 1:
        canvas.after(100, micek)

def stop(souradnice):
    global pokracovat
    if pokracovat == 1:
        pokracovat = 0
    else:
        pokracovat = 1
        micek()

pokracovat = 1
x = 200
y = 5
micek()
canvas.bind('<ButtonPress-1>', stop)

canvas.mainloop() #povinné ve VSCode

Jedničky a nuly

Vytvořte program 14_jednicky_nuly.py, který bude postupně zapisovat na plátno 0 nebo 1 (náhodně vybrané):

Program bude mít následující vlastnosti:

  1. Program začne zapisovat od levého horního rohu v jednom řádku, dokud ho nezaplní.
  2. Když se jeden řádek zaplní, bude pokračovat v zápisu na další řádek. Můžete určit, kolik čísel má být na řádku (v ukázce je jich 8).
  3. Barvy číslic 0 a 1 jsou odlišné.
  4. Po stisknutí klávesy P se výstup zastaví (pauza).
  5. Opětovným stisknutím klávesy P se pozastavený výstup obnoví.
  6. Po zaplnění celé obrazovky program skončí.
  7. Program po ukončení do terminálu vypíše počty zapsaných jedniček a nul.

Kolize

Vytvořte program 14_kolize.py , který má následující vlastnosti:

  1. Modrá kulička se pohybuje vodorovně od levého okraje vpravo.
  2. Od pravého okraje se červená kulička pohybuje vodorovně doleva.
  3. V každém kroku posunu kuličky (každá zvlášť) zvolí program velikost posunu od 5 do 10 pixelů (náhodně).
  4. Animace se zastaví, když se kuličky setkají.
  5. V místě srážky se něco zobrazí, například “BUM”.
  6. Animace bude naprogramována v jedné funkci (použijte pouze jeden časovač).

Dostihy

Vytvořte program 14_dostihy.py simulující dostihový závod, který má následující vlastnosti:

  1. Kousek od pravého okraje grafické plochy stojí tři koně na startu – tři kolečka různých barev svisle pod sebou (s rozestupy).
  2. Kousek od levého okraje je svislá čára reprezentující cílovou pásku.
  3. Koně se v každém kroku posunují směrem doleva (k cíli) o náhodný krok od 1 do 15 pixelů.
  4. Animace se zastaví, když jeden kůň vyhraje – doběhne do cíle.
  5. Cílová páska se stále zobrazuje .
  6. Pro zdatnější: Do grafické plochy se vypíše vítězný kůň, např. “Vyhrál žlutý kůň”.